Introduction
============

These are notes from converting the Spectrum 48KB game "Mayhem" to the PCW in a way that would 
likely happen 'back in the day'.

The original game was written by the author Mark Incley when he was 15 years old. A big thankyou for his permission 
to convert it. Visit his website at: http://www.inkland.org.uk/

See the Spectrum version at: https://worldofspectrum.org/archive/software/games/mayhem-the-power-house

The PCW version exists as a single .COM file which is loaded from CP/M which then takes over the
machine. Back in the day both .COM files and custom boot discs were used. It is being distributed 
as a .COM file so that it can be put onto a disk with other games.

The PCW and CPC version share similarities:
- Mostly the same code base.
- All graphics must be done as bitmaps and no tricks to change colours with attributes can be used.
- same keyboard controls

All the game play changes are on the PCW. Some of the memory saving choices from the CPC version were used on the PCW
version although there was much less need with the PCW having more RAM. The most important bit was keeping the common
code in the memory region 0-7fff, with 8000-ffff used for screen etc.

Thankyou to Habi for answering my many questions about the PCW! :)

Please support the PCW Wiki:
https://habisoft.com/pcwwiki

CP/M Box the emulator I used:
https://habisoft.com/pcw

Loading
=======

It is unclear what loader would be used on the PCW back in the day.

I chose to use a COM file which you can run from CPM.

1. Boot CPM on the PCW.
2. Insert Mayhem disc into drive A
3. Type: MAYHEM to load.

Sound
=====

The PCW has a fixed 4Khz 85decibel beeper which is on the PCW motherboard inside the PCW's monitor case. This can be turned on or off via one of the 
I/O ports. Since this beeper is inside the case and not via a speaker then it's volume is reduced and the noise is affected by the case itself.

I did look into converting the Spectrum 48K beeper sounds and did convert some of them. There was one issue 
where the explosion sound used read from the Spectrum ROM and converted that to beeper sound. I could not convert this
accurately. The other sounds were close enough. In the end I chose not to convert the beeper sound.
 
If Dk'Tronics sound is chosen from the menu then the game will assume a Dk'Tronics joystick/sound device is connected and
try and use the on-board AY-3-8910 sound chip on it. The AY-3-8912 on this device is clocked at 1Mhz 
(same as Amstrad CPC) and provides stereo sound through speakers and therefore the CPC sounds could be used directly.


Scrolling message
=================

On the Spectrum there is a scrolling message to show the chosen controls on the main menu. With the PCW I also 
want to allow the selection of audio and waiting for two scrolling messages I felt was too slow for the main menu.
So I removed the scrolling messages from the PCW version.

Framerate
=========

Like the CPC the frame rate is locked to 25fps.

Joysticks
=========

The PCW supports more than 1 joystick interface which can be attached to the PCW with Kempston and Dk'Tronics 
being the most common.

If Dk'Tronics is selected the joystick will be scanned and AY based sound effects will be used. The joystick will not 
be scanned if it's not selected since scanning involves using I/O ports which only exist when the hardware is attached
and which could clash with other hardware.

Joysticks - Scanning
====================

The PCW has multiple joystick devices like the spectrum

1. Keystick - mapped to keyboard line, read the same as keyboard

Scanning the Keystick is slower than on the Spectrum.

2. Joystick interface on Dk'Tronics interface is connected via the AY sound chip on that interface.

On the PCW reading the Dk'Tronics joystick:

;; select port 14 of AY in Dk'Tronics interface
ld a,&e
out (&aa),a
;; read joystick.
in a,(&a9)

Scanning this joystick is slower than on the Spectrum.


3. Kempston Joystick interface.

The Spectrum also has a Kempston Joystick interface and it is scanned with:

in a,(&1f)

On the PCW it is scanned with:

in a,(&9f)

Scanning the kempston Joystick interface is the same speed as on the Spectrum.


Screen
======

The PCW has a 2 colour bitmapped display. The screen can't be re-sized like it can on the CPC, however it has 512 
bytes of 'roller ram' which define the  start memory address of each scan-line. Therefore it can be 're-sized'
vertically by pointing multiple lines to the same address in memory.

There are also 50hz and 60hz variants of the PCW which support 256 lines and 200 lines respectively and this should
be taken into account. I do by centralising the screen vertically.

This game doesn't use all of the vertical display therefore the display is centred vertically using 
I/O port F6 and any lines that are not used are defined in the roller ram to point to the same 90 byte blank line.

The width of the screen can't be changed and takes a fixed number of bytes (90*8 per scanline where multiple
scanlines are interleaved). This means a line starting at offset '0' used, 0,8,16 etc but we can also have a line
starting at offset '1' which uses 1,9,17 etc. In this way a continuous block of memory is used for screen pixels.

The game  uses only part of the horizontal line so the screen is centralised horizontally with 
padding on the left and right which is set to 0. Therefore there is some wastage here.

Like the CPC version the PCW version uses double buffering.

Screen 1 uses pages 0 and 1.
Screen 2 uses pages 2 and 3.

The screen being drawn to is always paged into CPU memory between &8000-&ffff. This simplifies the 
sprite drawing since it is always drawing in the range 8000-ffff.

The sprites and graphics are displayed as if the PCW had a 3 tone mode (none, mid, bright) and a square 
pixel ratio. This is closest to Spectrum and CPC's mode 1 resolution. Each 'pixel' is formed from two pixels side by side:

For each byte:

a1 a0 b1 b0 c1 c0 d1 d0

For 'a':

a1/a0
0  0 - none
1  0 - mid
0  1 - mid
1  1 - bright

Each screen has it's own pixels and it's own 'roller ram' definition. There are some otherwise unused 
areas of 'screen ram' and for ease and speed some data is duplicated in these areas. 

The memory organisation is:

Each line uses 90 bytes but each byte is separated by 8 bytes.

&8000-&c3da - 18,000 bytes - 90 bytes wide, 192 lines tall. If the screen is a multiple of 8 tall, then each 90 byte line follows on from the previous. This data is contiguous. Only 64 bytes of each line is used
for pixels, but all are displayed by hardware. More than 1 16KB page is needed since even with 192 lines tall this results in 17,280 bytes for pixels alone so more 
than 16384 bytes in one page. One pixel line is repeated for the area above and below the visible. This is a min of 720 bytes
with every 8 bytes used because of the layout of pcw screen memory. 

&df00-&ed00 (repeated) Storage for background behind sprites.

&ed00-&fbff (repeated)  pixel shift table for sprite pixels. 7 tables, 512 bytes each. A sprite can be positioned up to 8 pixels. Could be 3 tables to reduce data?

&fc00-feff is for roller 'ram' - 512 bytes fixed size - defines the start address of every line. 256 lines for PAL. Restrictions with having keyboard readable meant we 
couldn't put it at &fd00

&ff00-&ffef is unused - 240 bytes

&fff0-&ffff is where the keyboard maps in page 3. 16 bytes. Unused in pages 0,1 and 2.

NOTE: It is possible to store additional sprites or tiles within the screen memory. This would require CPU memory in the range 0000-&7fff to be paged out to access.

Screen addressess
=================

We store a list of screen addresses for the start of each line to aid calculating screen addresses.

When drawing a sprite it is done left to right, top to bottom, note that however to move to the next screen address requires adding 8 to 
the address which is often done as follows:

ld a,l
add a,8
ld l,a
ld a,h
adc a,0
ld h,a

On Spectrum the equivalent is a simple:

inc l

The calculation to go to the next line is complex like the Spectrum so there is little difference here.


Memory
======

The PCW's "CPC 'standard' paging mode" is used. For each 16KB page this allows to define a page that is read 
from idenpendently from a page that is written to. Normally in the standard PCW paging mode the same page is 
enabled for both read and write.

This 'CPC 'standard' paging mode' is used when drawing opaque graphics such as tiles where it is not necessary to 
read from the screen. Therefore opaque pixels are located at &8000 and above in pages 6,7. Opaque pixels include the font, the tiles for the levels and the
in-level pictures.

Any 'transparent'/'masked' sprites used the standard PCW mode to enable read and write since the screen memory
must be read, ANDed, ORed and written back. Transparent graphics are stored below &8000. This includes all player and enemy sprites.

Therefore to take advantage of this the CPC and PCW memory layout differ.

Graphics
========

The graphics have been adapted from the Spectrum and the following has been done which works better with the PCWs graphics display:

- Use the pseudo 3-colour 'graphics mode'
- All background graphics will be black or grey. Walls have been made more obvious and the floor tiles have been simplified. 
- All sprites, interactables and enemies will be brighter than the background so they stand out.

This stops the sprites blending into the background making it easier to read the gameplay.

C64 exploding
=============

When the C64 is shot it will explode. The Spectrum version re-uses the explosion sprites but draws them opaque and it can do that with
the normal opaque drawing code because the pixels are separate from the mask and are not interleaved.


Tiles:
======

A tile which is 16x16 pixels in '3 colour mode' is effectively 32x16 pixels. The underlying storage is normal 8 pixels
per byte or 4 '3 colour' pixels. Therefore the storage for a tile is (32/8)*16 = 64 bytes.


Spectrum:

* 1bpp
* 16x16. 
* Each tile's pixels takes 32 bytes. 
* 64 tiles. 
* Attribute data for 64 tiles (2x2 attributes)

Total: (64*32)+(64*4) = 2304 bytes.

PCW:

* effectively 2bpp
* 16x16
* Each tile's pixel takes 64 bytes
* 64 tiles
* No attribute data

Total: (64*64) = 4096 bytes

The tiles take the same space as the CPC. The tiles are opaque so can be stored in the range &8000-&ffff. 

Sprites:
========

Since we have very few colours, to be able to use all '3 colours' a mask is stored in addition to the sprites 
pixel data. Therefore for a sprite which is 16x16 on Spectrum, the dimensions for pixels is 32x16 and the
dimensions for mask is 32x16.

Each 'pixel' in the mask is also 2 bits just like the 'pixel' in the sprite.

Therefore storage per sprite is:

(32/8)*16*2 = 128 bytes.

Spectrum:

* 1bpp
* 16x16. 
* No attribute data
* Graphics 16x16 followed by mask 16x16. This allows the same graphics to be re-used as opaque if required.
* Each sprite takes 64 bytes.
* No shift table, graphics shifted as they are drawn

PCW:

* 2bpp
* 16x16. 
* Graphics 16x16 with mask 16x16, interleaved, 1 byte of mask, 1 byte of graphics
* Each sprite takes 128 bytes. 
* 3 tables to shift sprite to 4 different pixel positions

All sprites with masks need to be accessible below <&8000 since the screen is paged in from &8000-&ffff.


Sprite deletion
===============

Sprite drawing:
- delete sprite from old position 
- draw sprite in new position

To delete the sprite we capture the background before the sprite is drawn. This is then copied before the sprite is drawn in the new position.

To capture the background we need to be able to read the screen. To write the background back to delete the sprite we need to write to the screen.
Therefore storing this data within spare screen memory (&8000-&ffff) makes sense.

The background for the sprite is stored in the same screen memory area it was drawn to. Since the screens are double buffered that does mean 2 sets
of data are required to restore the sprites. The screen memory is always paged into the same location so the data is stored in the same place for each
screen.


Keyboard
========

The PCW has a memory mapped keyboard. 

On the Spectrum the following is the minimum required to read a keyboard line (8 keys at once):

ld      a,0bfh			; Select keyboard line
in      a,(0feh)    ; read keyboard line

On the PCW, first page in the memory where the keyboard is, read the key from memory and restore the page back to how it was:

;; select keyboard page
ld a,&83
out (&f3),a
;; read keyboard line (8 keys at once)
ld a,(&fff0)

;; restore page
ld a,(previous_f3)
out (&f3),a

Joystick
========

The PCW has multiple joystick devices like the spectrum

1. Keystick - mapped to keyboard line, read the same as keyboard

Scanning the Keystick is slower than on the Spectrum.
